using System;
using System.Data;
using System.Windows.Forms;
using DevExpress.Utils;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraGrid.Views.Grid;
using E4RPDevExpress10;
using E4RPTools;
using Movements.DataSet;

namespace Movements.Controls
{
    public partial class MovementXtraForm : XtraForm
    {
        private long _documentId;
        private Controller _controller;
        private MovimentoDataSet _dataSet;
        private DataView _clone;
        private bool _loading;
        private ProdutoFornecedorDataSet _productSupplierData;

        #region Properties

        public long DocumentId
        {
            set { _documentId = value; }
        }

        public Controller Controller
        {
            set
            {
                _controller = value;
                productsXtraUserControl.Controller = _controller;
            }
        }

        #endregion

        public MovementXtraForm()
        {
            InitializeComponent();
            printCheckEdit.Checked = false;
            _productSupplierData = new ProdutoFornecedorDataSet();
            DevExpressHelper.SetColumnAsNumeric(colQuantidade);
            Load += MovementXtraFormLoad;
            typeLookUpEdit.EditValueChanging += TypeLookUpEditEditValueChanging;
            supplierRepositoryItemLookUpEdit.CloseUp += SupplierRepositoryItemLookUpEditCloseUp;
            productsXtraUserControl.ProductSelected += ProductsXtraUserControlProductSelected;            
            gridView.ShownEditor += GridViewShownEditor;
            gridView.HiddenEditor += GridViewHiddenEditor;
            gridView.CustomUnboundColumnData += GridViewCustomUnboundColumnData;
            oKSimpleButton.Click += OkSimpleButtonClick;
        }

        #region

        private void MergeData()
        {
            _dataSet = new MovimentoDataSet();
            if (_documentId <= 0)
            {
                var movement = _dataSet.Movimento.NewMovimentoRow();
                movement.Id = _documentId;
                movement.Data = DateTime.Now;
                movement.Nome = "";                
                _dataSet.Movimento.AddMovimentoRow(movement);                
            }
            else
                _dataSet.Merge(_controller.GetMovement(_documentId));
        }

        private void SetupMovementTypeLookupData()
        {
            tipoMovimentoDataSet = _controller.GetMovementTypes();
            typeLookUpEdit.Properties.Columns.Clear();
            typeLookUpEdit.Properties.Columns.AddRange(new[] {
                    new LookUpColumnInfo("Tipo", "Tipo", 81, FormatType.None, "", false, HorzAlignment.Near),
                    new LookUpColumnInfo("Nome", "Nome", 85, FormatType.None, "", true, HorzAlignment.Near)});
            typeLookUpEdit.Properties.DisplayMember = tipoMovimentoDataSet.TipoMovimento.NomeColumn.ColumnName;
            typeLookUpEdit.Properties.ValueMember = tipoMovimentoDataSet.TipoMovimento.TipoColumn.ColumnName;
            typeLookUpEdit.Properties.DataSource = tipoMovimentoDataSet.TipoMovimento;            
        }

        private void SetupTargetEntityLookupData()
        {
            equipamentoDestinoDataSet = _controller.GetTargetEntities();
            targetEntityLookUpEdit.Properties.Columns.Clear();
            targetEntityLookUpEdit.Properties.Columns.AddRange(new[] {
                new LookUpColumnInfo("Id", "Id", 81, FormatType.None, "", false, HorzAlignment.Near),
                new LookUpColumnInfo("Nome", "Nome", 85, FormatType.None, "", true, HorzAlignment.Near)});
            targetEntityLookUpEdit.Properties.DisplayMember = equipamentoDestinoDataSet.EntidadeDestino.NomeColumn.ColumnName;
            targetEntityLookUpEdit.Properties.ValueMember = equipamentoDestinoDataSet.EntidadeDestino.IdColumn.ColumnName;
            targetEntityLookUpEdit.Properties.DataSource = equipamentoDestinoDataSet.EntidadeDestino;
        }

        private void SetupProductLookupData()
        {
            produtoDataSet = _controller.GetProducts();
            productRepositoryItemLookUpEdit.Columns.Clear();
            productRepositoryItemLookUpEdit.Columns.AddRange(new[] {
                new LookUpColumnInfo("Id", "Id", 81, FormatType.None, "", false, HorzAlignment.Near),
                new LookUpColumnInfo("Designacao", "Designacao", 85, FormatType.None, "", true, HorzAlignment.Near)});
            productRepositoryItemLookUpEdit.DisplayMember = produtoDataSet.Produto.DesignacaoColumn.ColumnName;
            productRepositoryItemLookUpEdit.ValueMember = produtoDataSet.Produto.IdColumn.ColumnName;
            productRepositoryItemLookUpEdit.DataSource = produtoDataSet.Produto;           
        }

        private void SetupSupplierLookupData()
        {
            supplierRepositoryItemLookUpEdit.Columns.Clear();
            supplierRepositoryItemLookUpEdit.Columns.AddRange(new[] {
                new LookUpColumnInfo("IdFornecedor", "IdFornecedor", 81, FormatType.None, "", false, HorzAlignment.Near),
                new LookUpColumnInfo("Nome", "Nome", 85, FormatType.None, "", true, HorzAlignment.Near),
                new LookUpColumnInfo("Referencia", "Referencia", 120, FormatType.None, "", true, HorzAlignment.Near)});
            supplierRepositoryItemLookUpEdit.DisplayMember = _productSupplierData.ProdutoFornecedor.NomeColumn.ColumnName;
            supplierRepositoryItemLookUpEdit.ValueMember = _productSupplierData.ProdutoFornecedor.IdFornecedorColumn.ColumnName;
            supplierRepositoryItemLookUpEdit.DataSource = _productSupplierData.ProdutoFornecedor;
            supplierRepositoryItemLookUpEdit.BestFit();
        }

        private void SetDataToControls()
        {
            dateEdit.EditValue = _dataSet.Movimento[0].Data;
            nameTextEdit.Text = _dataSet.Movimento[0].Nome;
            typeLookUpEdit.EditValue = _dataSet.Movimento[0].IsTipoNull() ? "" : _dataSet.Movimento[0].Tipo;
            targetEntityLookUpEdit.EditValue = _dataSet.Movimento[0].IsIdEntidadeDestinoNull() ? Convert.DBNull : _dataSet.Movimento[0].IdEntidadeDestino;
            gridControl.DataSource = null;
            gridControl.DataMember = "";
            gridControl.DataSource = _dataSet;
            gridControl.DataMember = _dataSet.ItemMovimento.TableName;
            targetEntityLookUpEdit.Enabled = !_dataSet.Movimento[0].IsIdEntidadeDestinoNull();
        }
        
        private void GetDataFromControls()
        {
            if (_documentId <= 0)
                _dataSet.Movimento[0].IdUtilizador = _controller.LoggedUserId;
            _dataSet.Movimento[0].Data = Convert.ToDateTime(dateEdit.EditValue);
            _dataSet.Movimento[0].Nome = nameTextEdit.Text;
            _dataSet.Movimento[0].Tipo = typeLookUpEdit.EditValue.ToString();
            if (targetEntityLookUpEdit.EditValue == Convert.DBNull || Convert.ToInt64(targetEntityLookUpEdit.EditValue) == -1)
                _dataSet.Movimento[0].SetIdEntidadeDestinoNull();
            else 
                _dataSet.Movimento[0].IdEntidadeDestino = Convert.ToInt64(targetEntityLookUpEdit.EditValue);
            _dataSet.Movimento[0].DataAlteracao = DateTime.Now;
            _dataSet.Movimento[0].IdUtilizadorAlteracao = _controller.LoggedUserId;
            gridView.CloseEditor();
            gridView.UpdateCurrentRow();
        }

        private void ClearControlErrors()
        {
            dxErrorProvider.SetError(dateEdit, "");
            dxErrorProvider.SetError(nameTextEdit, "");
            dxErrorProvider.SetError(typeLookUpEdit, "");            
            dxErrorProvider.SetError(targetEntityLookUpEdit, "");
            dxErrorProvider.SetError(gridControl, "");
        }

        private Control GetControl(string reference)
        {
            switch (reference)
            {
                case "Data":
                    return dateEdit;
                case "Nome":
                    return nameTextEdit;
                case "Tipo":
                    return typeLookUpEdit;
                case "IdEntidadeDestino":
                    return targetEntityLookUpEdit;
                case "ItemMovimento":
                    return gridControl;
                default:
                    return null;
            }
        }

        private void SetControlErrors(Result result)
        {
            foreach (var error in result.Errors)
            {
                dxErrorProvider.SetError(GetControl(error.Reference), error.Message);
                if (error.Reference == "ItemMovimento")
                    MessageBox.Show(this, error.Message, "Movimento", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private long GetNextMovementItemId()
        {
            long lastId = 0;
            foreach (MovimentoDataSet.ItemMovimentoRow movementItem in _dataSet.ItemMovimento)
            {
                var id = movementItem.RowState == DataRowState.Deleted ? Convert.ToInt64(movementItem["id_item", DataRowVersion.Original]) : movementItem.IdItem;
                if (id < lastId)
                    lastId = id;
            }
            return lastId - 1;
        }

        private void AddProduct(long productId)
        {
            gridView.CloseEditor();
            gridView.UpdateCurrentRow();
            var product = produtoDataSet.Produto.FindById(productId);
            var movementItem = _dataSet.ItemMovimento.NewItemMovimentoRow();
            movementItem.Id = _dataSet.Movimento[0].Id;
            movementItem.IdItem = GetNextMovementItemId();
            movementItem.Quantidade = 1;
            movementItem.IdProduto = productId;
            if (product.GetFornecedorRows().Length == 1)
                movementItem.IdFornecedor = product.GetFornecedorRows()[0].IdFornecedor;
            movementItem.Valor = movementItem.IsIdFornecedorNull()
                                     ? 0
                                     : _productSupplierData.ProdutoFornecedor.FindByIdProdutoIdFornecedor(movementItem.IdProduto, movementItem.IdFornecedor).Valor;
            _dataSet.ItemMovimento.AddItemMovimentoRow(movementItem);
        }

        private void SetReadonly()
        {
            dateEdit.Enabled = false;
            nameTextEdit.Enabled = false;
            typeLookUpEdit.Enabled = false;
            targetEntityLookUpEdit.Enabled = false;
            colId.OptionsColumn.AllowEdit = false;
            colIdItem.OptionsColumn.AllowEdit = false;
            colIdProduto.OptionsColumn.AllowEdit = false;
            colIdFornecedor.OptionsColumn.AllowEdit = false;
            colQuantidade.OptionsColumn.AllowEdit = false;
            colObservacoes.OptionsColumn.AllowEdit = false;
            colProdutoReferencia.OptionsColumn.AllowEdit = false;
            colValor.OptionsColumn.AllowEdit = false;
            colFornecedorReferencia.OptionsColumn.AllowEdit = false;
            colUnidade.OptionsColumn.AllowEdit = false;
            gridControl.EmbeddedNavigator.Buttons.Remove.Enabled = false;
            productsXtraUserControl.ReadOnly = true;
        }

        private bool ExitStockValid()
        {
            var result = _controller.IsExitMovementStockValid(_dataSet);
            if(!result.Failed)
                return true;
            var message = "";
            foreach (var error in result.Errors)
                message += error.Message + Environment.NewLine;
            return MessageBox.Show(this, message + "Deseja prosseguir?", "Movimento", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.No;
        }

        private bool SupplierReturnStockValid()
        {
            var result = _controller.IsSupplierReturnMovementStockValid(_dataSet);
            if(!result.Failed)
                return true;
            var message = "";
            foreach (var error in result.Errors)
                message += (message.Length == 0 ? "" : Environment.NewLine) + error.Message;
            MessageBox.Show(this, result.Errors[0].Message, "Movimento", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }

        private bool ReturnStockValid()
        {
            var result = _controller.IsReturnMovementStockValid(_dataSet);
            if (!result.Failed)
                return true;
            var message = "";
            foreach (var error in result.Errors)
                message += (message.Length == 0 ? "" : Environment.NewLine) + error.Message;
            MessageBox.Show(this, message, "Movimento", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }

        private bool StockValid()
        {
            switch(_dataSet.Movimento[0].Tipo)
            {
                case "S":
                    return ExitStockValid();
                case "F":
                    return SupplierReturnStockValid();
                case "D":
                    return ReturnStockValid();
                default:
                    return true;
            }
        }

        private void ResetValue(bool enable)
        {
            if (enable) 
                return;
            foreach(MovimentoDataSet.ItemMovimentoRow movementItem in _dataSet.ItemMovimento)
            {
                if (movementItem.IsIdFornecedorNull())
                    continue;
                if (movementItem.RowState == DataRowState.Added || movementItem.RowState == DataRowState.Modified)
                    movementItem.Valor = _productSupplierData.ProdutoFornecedor.FindByIdProdutoIdFornecedor(movementItem.IdProduto, movementItem.IdFornecedor).Valor;
            }
        }

        #endregion

        void MovementXtraFormLoad(object sender, EventArgs e)
        {
            _loading = true;
            _productSupplierData = _controller.GetProductSupplier();
            MergeData();
            SetupMovementTypeLookupData();
            SetupTargetEntityLookupData();
            SetupProductLookupData();
            SetupSupplierLookupData();
            SetDataToControls();
            if (_controller != null)
            {
                productsXtraUserControl.Populate();
                if (_controller.LoggedUserProfile != (int) UserProfile.Administrator && _documentId > 0)
                    SetReadonly();
            }
            _loading = false;
        }

        void TypeLookUpEditEditValueChanging(object sender, ChangingEventArgs e)
        {
            if(_loading)
                return;
            if (e.NewValue == null || e.NewValue.ToString() == "C" || e.NewValue.ToString() == "F")
            {
                targetEntityLookUpEdit.EditValue = Convert.DBNull;
                targetEntityLookUpEdit.Enabled = false;
            }
            else
            {
                targetEntityLookUpEdit.Enabled = true;
            }
            colValor.OptionsColumn.AllowEdit = e.NewValue != null && e.NewValue.ToString() == "C";
            ResetValue(e.NewValue != null && e.NewValue.ToString() == "C");
        }

        void ProductsXtraUserControlProductSelected(object sender, ProductEventArgs e)
        {
            AddProduct(e.ProductId);
        }        

        void GridViewShownEditor(object sender, EventArgs e)
        {
            var view = sender as GridView;
            if (view == null)
                return;
            if (view.FocusedColumn != colIdFornecedor) 
                return;
            var lookUpEdit = (LookUpEdit)view.ActiveEditor;
            var focusedRow = view.GetDataRow(view.FocusedRowHandle);
            if (focusedRow == null)
                return;
            _clone = new DataView(_productSupplierData.ProdutoFornecedor) { RowFilter = "IdProduto=" + focusedRow["IdProduto"] };
            lookUpEdit.Properties.DataSource = _clone;
        }

        void GridViewHiddenEditor(object sender, EventArgs e)
        {
            if (_clone == null) return;
            _clone.Dispose();
            _clone = null;
        }

        void SupplierRepositoryItemLookUpEditCloseUp(object sender, CloseUpEventArgs e)
        {
            if (Convert.IsDBNull(e.Value))
                return;
            var movementItem = (MovimentoDataSet.ItemMovimentoRow)gridView.GetDataRow(gridView.FocusedRowHandle);
            var value = e.Value == null ? 0 : _productSupplierData.ProdutoFornecedor.FindByIdProdutoIdFornecedor(movementItem.IdProduto, Convert.ToInt64(e.Value)).Valor;    
            gridView.SetFocusedRowCellValue(colValor, value);            
            gridView.RefreshRow(gridView.FocusedRowHandle);
        }

        void GridViewCustomUnboundColumnData(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDataEventArgs e)
        {
            var movementItem = (MovimentoDataSet.ItemMovimentoRow)gridView.GetDataRow(e.RowHandle);
            if (movementItem == null)
                return;
            if (e.Column == colUnidade)
                e.Value = produtoDataSet.Produto.FindById(movementItem.IdProduto).IsUnidadeNull() ? "" : produtoDataSet.Produto.FindById(movementItem.IdProduto).Unidade;
            if (e.Column == colProdutoReferencia)
                e.Value = produtoDataSet.Produto.FindById(movementItem.IdProduto).Referencia;
            if (e.Column == colFornecedorReferencia && !movementItem.IsIdFornecedorNull())
            {
                var productSupplier = _productSupplierData.ProdutoFornecedor.FindByIdProdutoIdFornecedor(movementItem.IdProduto, movementItem.IdFornecedor);
                e.Value = productSupplier.IsReferenciaNull() ? "" : productSupplier.Referencia;
            }                       
        }       

        void OkSimpleButtonClick(object sender, EventArgs e)
        {
            if (_controller.LoggedUserProfile == (int)UserProfile.Administrator)
            {
                ClearControlErrors();
                GetDataFromControls();
                var result = _controller.IsMovementValid(_dataSet);
                if (result.Failed)
                {
                    DialogResult = DialogResult.None;
                    SetControlErrors(result);
                    return;
                }
                if (!StockValid())
                {
                    DialogResult = DialogResult.None;
                    return;
                }
                _controller.SaveMovement(_dataSet);
            }
            if(printCheckEdit.Checked)
                _controller.PrintMovement(_dataSet.Movimento[0].Id);
        }
        
    }
}